package cn.tedu.mall.seckill.service.impl;

import cn.tedu.mall.common.config.PrefixConfiguration;
import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.JsonPage;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.pojo.product.vo.SpuDetailStandardVO;
import cn.tedu.mall.pojo.product.vo.SpuStandardVO;
import cn.tedu.mall.pojo.seckill.model.SeckillSpu;
import cn.tedu.mall.pojo.seckill.vo.SeckillSpuDetailSimpleVO;
import cn.tedu.mall.pojo.seckill.vo.SeckillSpuVO;
import cn.tedu.mall.product.service.seckill.IForSeckillSpuService;
import cn.tedu.mall.seckill.mapper.SeckillSpuMapper;
import cn.tedu.mall.seckill.service.ISeckillSpuService;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class SeckillSpuServiceImpl implements ISeckillSpuService {
    //装配查询秒杀信息的mapper
    @Autowired
    private SeckillSpuMapper seckillSpuMapper;
    //查询spu常规信息，需要dubbo调用product模块
    @DubboReference
    private IForSeckillSpuService dubboSeckillSpuService;

    //分页查询秒杀商品信息
    // 返回值SeckillSpuVO是一个既包含spu常规信息,又包含spu秒杀信息的对象
    // 我们需要从mall_seckill数据库获得秒杀信息,从mall_pms数据库获取常规信息
    @Override
    public JsonPage<SeckillSpuVO> listSeckillSpus(Integer page, Integer pageSize) {
        PageHelper.startPage(page,pageSize);
        List<SeckillSpu> seckillSpus = seckillSpuMapper.findSeckillSpus();
        List<SeckillSpuVO> seckillSpuVOS = new ArrayList<>();
        for (SeckillSpu seckillSpu : seckillSpus){
            //获取spuid
            Long spuId = seckillSpu.getSpuId();
            //根据spuIId，dubbo查询对应的商品常规信息
            SpuStandardVO spuStandardVO = dubboSeckillSpuService.getSpuById(spuId);
            //实例化SeckillSpuVO对象，用于接收常规信息和秒杀信息
            SeckillSpuVO seckillSpuVO = new SeckillSpuVO();
            //将常规信息，赋值到seckillSpuVO
            BeanUtils.copyProperties(spuStandardVO,seckillSpuVO);
            //常规信息赋值完毕，把秒杀信息赋值到seckillSpuVO
            seckillSpuVO.setSeckillListPrice(seckillSpu.getListPrice());
            seckillSpuVO.setStartTime(seckillSpu.getStartTime());
            seckillSpuVO.setEndTime(seckillSpu.getEndTime());
            //将包含常规信息和秒杀信息的对象添加到集合
            seckillSpuVOS.add(seckillSpuVO);
        }
        return JsonPage.restPage(new PageInfo<>(seckillSpuVOS));
    }

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public SeckillSpuVO getSeckillSpu(Long spuId) {
        // 在后面的完整版代码中,我们在这里编写布隆过滤器判断
        // 如果布隆过滤器中不包含参数spuId的值,抛出异常,终止方法,防止缓存穿透

        // 当前业务是会将从数据库查询出的信息保存到Redis的,所以先检查Redis中有没有
        // mall:seckill:spu:vo:2
        String spuVOKey = SeckillCacheUtils.getSeckillSpuVOKey(spuId);
        SeckillSpuVO seckillSpuVO = null;
        if (redisTemplate.hasKey(spuVOKey)){
            seckillSpuVO = (SeckillSpuVO) redisTemplate.boundValueOps(spuVOKey).get();
        }else {
            SeckillSpu seckillSpu = seckillSpuMapper.findSeckillSpuById(spuId);
            if (seckillSpu==null){
                throw new CoolSharkServiceException(ResponseCode.NOT_FOUND,"你要访问的商品不存在");
            }
            SpuStandardVO spuStandardVO = dubboSeckillSpuService.getSpuById(spuId);
            seckillSpuVO = new SeckillSpuVO();
            BeanUtils.copyProperties(spuStandardVO,seckillSpuVO);
            seckillSpuVO.setSeckillListPrice(seckillSpu.getListPrice());
            seckillSpuVO.setStartTime(seckillSpu.getStartTime());
            seckillSpuVO.setEndTime(seckillSpu.getEndTime());
            redisTemplate.boundValueOps(spuVOKey).set(seckillSpuVO,1000*60*5+ RandomUtils.nextInt(10000), TimeUnit.MILLISECONDS);
        }
        LocalDateTime nowTime = LocalDateTime.now();
        if (seckillSpuVO.getStartTime().isBefore(nowTime) && nowTime.isBefore(seckillSpuVO.getStartTime())){
            String randCodeKey = SeckillCacheUtils.getRandCodeKey(spuId);
            if (!redisTemplate.hasKey(randCodeKey)){
                throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"当前随机码不存在");
            }
            String randCode = redisTemplate.boundValueOps(randCodeKey).get()+"";
            seckillSpuVO.setUrl("/seckill/"+randCode);
            log.info("商品详情对象构建完成，url书信为：{}",seckillSpuVO.getUrl());
        }
        return seckillSpuVO;
    }

    //根据spuId查询秒杀用spuDetail
    public static final String SECKILL_SPU_DETAIL_VO_PRRFIX="seckill:spu:detail:vo:";
    @Override
    public SeckillSpuDetailSimpleVO getSeckillSpuDetail(Long spuId) {
        String spuDetailKey = SECKILL_SPU_DETAIL_VO_PRRFIX+spuId;
        SeckillSpuDetailSimpleVO simpleVO = null;
        if (redisTemplate.hasKey(spuDetailKey)){
            simpleVO = (SeckillSpuDetailSimpleVO) redisTemplate.boundValueOps(spuDetailKey).get();
        }else {
            SpuDetailStandardVO spuDetailStandardVO = dubboSeckillSpuService.getSpuDetailById(spuId);
            simpleVO = new SeckillSpuDetailSimpleVO();
            BeanUtils.copyProperties(spuDetailStandardVO,simpleVO);
            redisTemplate.boundValueOps(spuDetailKey).set(simpleVO,1000*60*5+RandomUtils.nextInt(10000),TimeUnit.MILLISECONDS);
        }
        return simpleVO;
    }
}
